/**
 **********************************************************************************************************************
 * @file    cot_key.h
 * @brief   该文件提供按键动作识别功能函数原型
 **********************************************************************************************************************
 */

/* Define to prevent recursive inclusion -----------------------------------------------------------------------------*/
#ifndef _COT_KEY_H_
#define _COT_KEY_H_

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

/**
 * @brief      定义宏：启动按键新配置延迟更新替换
 *
 * @details    只有在按键空闲的状态下才真正更新配置信息，防止上层应用程序在某些场景更新时出现意想不到的问题
 *
 * @note       如果上层应用程序只有在初始化时才更新配置，那么可以关闭该功能，降低内存占用
 */
#define _CONFIG_DELAY_UPDATE_

/* Exported types ----------------------------------------------------------------------------------------------------*/

/* 触发方式定义 */
#define COT_KEY_TRIGGER_WAY_PRESS 0x01  /* 按下触发 - 按键按下时触发回调 */
#define COT_KEY_TRIGGER_WAY_LOSSEN 0x02 /* 松开触发 - 按键松开时触发回调 */

/**
 * @brief  按键状态枚举定义
 *
 * @details    用于表示按键的物理状态，分为按下和松开两种状态
 */
typedef enum
{
  COT_KEY_OFF = 0,          /* (0)断开(无动作) - 按键未被按下 */
  COT_KEY_ON = !COT_KEY_OFF /* (1)闭合(有动作) - 按键被按下 */
} cotKeyState_e;

/* 按键相关类型定义 */
typedef uint16_t cotKey_t;                    /* 按键索引类型 */
typedef cotKeyState_e (*cotKeyState_f)(void); /* 按键状态获取函数类型 */
typedef void (*cotKeyListen_f)(cotKey_t);     /* 按键事件回调函数类型 */

/**
 * @brief  按键配置信息结构体
 *
 * @details    用于配置按键的工作模式和触发方式
 */
typedef struct
{
  uint8_t mode;                    /* 按键模式:
                                      KEY_MODE_NORMAL(0)       - 普通模式
                                      KEY_MODE_LONG_PRESS(1)   - 长按模式
                                      KEY_MODE_CLICK(2)        - 连击模式
                                      KEY_MODE_CLICK_COMP(3)   - 连击复合模式 */
  uint8_t triggerWay;              /* 按键事件触发回调函数的触发条件:
                                      COT_KEY_TRIGGER_WAY_PRESS  - 按下触发
                                      COT_KEY_TRIGGER_WAY_LOSSEN - 松开触发 */
  uint16_t triggerInterval;        /* 长时间按下时触发回调函数的间隔时间(ms)
                                      0:不重复触发, >0:按指定间隔重复触发 */
  uint16_t longTime;               /* 区分短按和长按的时间阈值(ms)
                                      用于长按模式和连击复合模式 */
  cotKeyListen_f pfnEventCallback; /* 按键事件触发回调函数
                                      当按键动作满足触发条件时调用 */
} cotKeyInfo_t;

/**
 * @brief      按键处理信息结构体定义
 *
 * @details    用于记录按键的实时状态和处理过程
 */
typedef struct
{
  cotKeyState_e eKeyStateBak; /* 按键上次开关状态 - 用于检测状态变化 */
  cotKeyState_e eKeyState;    /* 按键当前开关状态 - 当前物理状态 */
  uint8_t clickCnt;           /* 指定所选按键的连击次数 - 用于连击模式 */
  uint16_t uiPressTic;        /* 按键按下累计时间(ms) - 用于长按检测 */
  uint16_t uiLossenTic;       /* 按键松开累计时间(ms) - 用于连击间隔检测 */
  uint8_t state;              /* 按键状态机状态:
                                 KEY_STATE_IDLE(0)        - 空闲
                                 KEY_STATE_PRESS(1)       - 按下
                                 KEY_STATE_LOSSEN(2)      - 松开
                                 KEY_STATE_LONG_PRESS(3)  - 长按
                                 KEY_STATE_LONG_LOSSEN(4) - 长按松开 */
  cotKeyInfo_t curConfig;     /* 按键当前配置 - 当前生效的配置 */
#if defined(_CONFIG_DELAY_UPDATE_)
  cotKeyInfo_t newConfig; /* 按键新的配置 - 待更新的配置
                             只在按键空闲时更新到curConfig */
#endif
} cotKeyProc_t;

/**
 * @brief      按键配置结构体
 *
 * @details    用于初始化按键模块时的配置信息
 */
typedef struct
{
  cotKeyProc_t proc;         /* 按键处理信息 */
  cotKeyState_f pfnKeyState; /* 按键状态获取函数 - 需要用户实现 */
} cotKeyCfg_t;

/* Exported constants ------------------------------------------------------------------------------------------------*/
/* Exported macro ----------------------------------------------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------------------------------------------------*/

/* 初始化按键模块 */
extern int cotKey_Init(cotKeyCfg_t pCfgTable[], size_t num);

/* 注册按键事件回调函数 */
extern int cotKey_Listen(cotKey_t eKey, cotKeyListen_f pfnKeyFun);

/* 配置按键模式 */
extern int cotKey_ResetDefaultConfig(cotKey_t eKey);
extern int cotKey_ConfigNormalMode(cotKey_t eKey, uint8_t triggerWay, uint16_t triggerInterval);
extern int cotKey_ConfigLongPressMode(cotKey_t eKey, uint16_t longPressTime, uint16_t triggerInterval);
extern int cotKey_ConfigClickMode(cotKey_t eKey, uint16_t triggerInterval);
extern int cotKey_ConfigClickCompMode(cotKey_t eKey, uint16_t triggerInterval, uint16_t pressMaxTime, uint8_t triggerWay);

/* 获取按键状态 */
extern uint8_t cotKey_GetClickCount(cotKey_t eKey);
extern bool cotKey_IsClickCount(cotKey_t eKey, uint8_t count);
extern bool cotKey_IsLongPress(cotKey_t eKey);
extern bool cotKey_IsTriggerWayMet(cotKey_t eKey, uint8_t triggerWay);
extern bool cotKey_IsPressTimeMet(cotKey_t eKey, uint8_t triggerWay, uint16_t time);
extern bool cotKey_IsLossenTimeMet(cotKey_t eKey, uint8_t triggerWay, uint16_t time);

/* 按键扫描处理函数(需要周期调用) */
extern int cotKey_Scan(uint32_t sysTime);

#endif
